#include "main.h"
#include "semantic_bridge.h"
#include "symbol_table.h"
#include "intercodegenerate.h"
#include "cJSON.h"

extern FILE* yyin;
extern char* yytext;
extern int yylineno;
extern int yycolumn;

// 递归转换AST节点为cJSON对象
cJSON* parse_node_to_json(ParseNode node) {
    if (node == NULL || node->lineno == -1) return NULL;

    cJSON* json_node = cJSON_CreateObject();
    
    // 添加基础字段
    cJSON_AddStringToObject(json_node, "name", node->name);
    if (node->lineno != -1) {
        cJSON_AddNumberToObject(json_node, "lineno", node->lineno);
    }

    // 处理不同节点类型
    if (strcmp(node->name, "ID") == 0) {
        cJSON_AddStringToObject(json_node, "value", node->ID);
    } else if (strcmp(node->name, "TYPE") == 0) {
        cJSON_AddStringToObject(json_node, "value", node->ID);
    } else if (strcmp(node->name, "INT") == 0) {
        cJSON_AddNumberToObject(json_node, "value", node->INT);
    } else if (strcmp(node->name, "FLOAT") == 0) {
        cJSON_AddNumberToObject(json_node, "value", node->FLOAT);
    }

    // 处理子节点
    if (node->num > 0) {
        cJSON* children = cJSON_CreateArray();
        for (int i = 0; i < node->num; i++) {
            cJSON* child = parse_node_to_json(node->child[i]);
            if (child != NULL) {
                cJSON_AddItemToArray(children, child);
            }
        }
        cJSON_AddItemToObject(json_node, "children", children);
    }

    return json_node;
}

// 导出AST到JSON文件
void export_ast_to_json(const char* filename) {
    cJSON* root = cJSON_CreateArray();
    
    for (int i = 0; i < nodeNum; i++) {
        if (isRoot[i] == 0) {
            cJSON* node_json = parse_node_to_json(nodeList[i]);
            if (node_json != NULL) {
                cJSON_AddItemToArray(root, node_json);
            }
        }
    }

    // 生成JSON字符串
    char* json_str = cJSON_Print(root);
    
    // 写入文件
    FILE* fp = fopen(filename, "w");
    if (fp) {
        fputs(json_str, fp);
        fclose(fp);
    }

    // 清理内存
    free(json_str);
    cJSON_Delete(root);
}

extern void yyrestart(FILE *);
extern int yyparse();

void setChild(ParseNode node){
	for(int i = 0; i < nodeNum; i++){
		if(node == nodeList[i]){
			isRoot[i] = 1;
		}
	}
}

ParseNode newNode(int yyline, int num, char* name, ParseNode child[]){
	ParseNode node = (ParseNode)malloc(sizeof(struct node));	// a new node
	ParseNode tmp  = (ParseNode)malloc(sizeof(struct node));	// temp
	
	node->name = name;
	node->num  = num;
	
	if(num > 0){	// new node is a father
		tmp = child[0];

		setChild(tmp);	// child[0] is not a root node

		node->child[0] = tmp;
		node->lineno = tmp->lineno;	// father's line number is similar with child 1

		for(int i = 1; i < num; i++){ // other children are not root, and link them
			tmp = child[i];
			setChild(tmp);
			node->child[i] = child[i];
		}

	} else {	// new node is a leaf node, also a terminal symbol(TS)
		node->lineno = yyline;	// TS's line number is equal to child 1(it has only one child)
		if(!strcmp(name, "ID")){	// the TS needed to compare are ID, TYPE, INT, FLOAT
			char *str;	// cannot use char str[40], it'll be error 
			str = (char *)malloc(sizeof(char) * 40);
			strcpy(str, yytext);	// copy the buffer to str

			node->ID = str;
		}
		else if(!strcmp(name, "TYPE")){
			char *str;	// same as the upper, cannot use char[]
			str = (char *)malloc(sizeof(char) * 40);
			strcpy(str, yytext);	// copy the buffer to str

			node->ID = str;
		}
		else if(!strcmp(name, "INT")){
			int number;
			number = atoi(yytext);

			node->INT = number;
		}
		else if(!strcmp(name, "FLOAT")){
			float number;
			number = atof(yytext);

			node->FLOAT = number;
		}
		else if(!strcmp(name, "RELOP")){
			char *tmp;
			tmp = (char *)malloc(sizeof(char) * 10);
			strcpy(tmp, yytext);

			node->ID = tmp;
		}
	}
	return node;
}

void preOrder(ParseNode node, int column) {
    if (node != NULL && node->lineno != -1) { // node exists and this is not a ε-expression(-1)
        for (int i = 0; i < column; i++) {
            printf(" ");
        }
        printf("%s", node->name);

        if (!strcmp(node->name, "ID")) {
            printf(": %s", node->ID);
        } else if (!strcmp(node->name, "TYPE")) {
            printf(": %s", node->ID);
        } else if (!strcmp(node->name, "INT")) {
            printf(": %d", node->INT);
        } else if (!strcmp(node->name, "FLOAT")) {
            printf(": %f", node->FLOAT);
        } else {
            if (node->num != 0) { // it's a nonterminal symbol, print its line number
                printf("(%d)", node->lineno);
            }
        }

        printf("\n");

        for (int i = 0; i < node->num; i++) { // print the children from left to right
            preOrder(node->child[i], column + 1);
        }
    }
}


void printTree(){
	if(!isFalse){
		// export_ast_to_json("ast.json");  // 导出为JSON文件
		for(int i = 0; i < nodeNum; i++){
			if(isRoot[i] == 0){	// this is the root node
				preOrder(nodeList[i], 0);
			}
		}
	}
}

void yyerror(const char *msg){ // for the B error
    isFalse = 1;
    fprintf(stderr, "Error type B at line %d, coloum %d: %s : %s.\n", yylineno, yycolumn, yytext, msg);
}

int main(int argc, char** argv) {    
	isFalse = 0; // determine whether the false happend, default is not
	nodeNum = 0;

	memset(nodeList, 0, sizeof(ParseNode)*1000);
	memset(isRoot, 0, sizeof(int)*1000);

	if (argc <= 1) return 1; 
	FILE* f = fopen(argv[1], "r"); 
	if (!f){
		perror(argv[1]); 
		return 1; 
	} 
	yyrestart(f); 
	yyparse(); 

	/* for(int i = 0; i < 20; i++){
		printf("%d, %s",i,nodeList[i]->name);
		printf("\n");
		for(int j = 0; j < 10; j++){
			if(nodeList[i]->child[j]){
				printf("%d, %s|",j,nodeList[i]->child[j]->name);
			}
		}
		printf("\n");
		printf("\n");
	} */

	if (!isFalse) {
		printf("\n\n");

		for(int i = 0; i < nodeNum; i++){
			if(isRoot[i] == 0){	// this is the root node
				semantic_check(nodeList[i]); 
				// generate_ir(nodeList[i]);

				// FILE* out = fopen("output.ir", "w");
				// print_ir(out);
				
				// fclose(out);

				translate_Program(nodeList[i]);
			}
		}

		// test_ir_generation();
    }

	test_ir_generation();

	return 0; 
}
